package co.edu.ucatolica.sislab.persistence.utils;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Utilizada para realizar la conexion a la base de datos.
 */
public class DAOFactory {
    /**
     * Logger de la clase.
     */
	private Logger logger = LoggerFactory.getLogger(DAOFactory.class);
   
    /**
     * Driver para conexion directa
     */
    protected DriverConfigurator configuradorDriver = null;
    
    /**
     * Indica cuantas conexiones se han abierto
     */
    private int numConexiones = 0;
    
    /**
     * Unica instancia de la clase
     */
    private static DAOFactory instancia = new DAOFactory();
    
    /**
     * Constructor
     */    
    private DAOFactory() {
        super();
        if ( PersistenceType.getInstancia().getTipoPersistencia() == PersistenceConstants.TIPO_CONEXIONDIRECTA ) {
        	configuradorDriver = DriverConfigurator.getInstancia();
        }

    }

    /**
     * Retorna la conexion si no esta definida o cerrada crea una nueva conexion.
     * @return Una conexion a la base de datos
     */
    public Connection getConexion( DatabaseTypes databaseType ) {
        Connection conexionBaseDatos = null;
        if ( PersistenceType.getInstancia().getTipoPersistencia() == PersistenceConstants.TIPO_CONEXIONDIRECTA ) {
        	logger.info("Crear conexion mediante Conexion Directa");
            try {
                if ( conexionBaseDatos == null || conexionBaseDatos.isClosed() ) {
                	ConnectionInformation ci = configuradorDriver.getConnectionInformation(databaseType);
                	if ( ci != null ) {
	                    conexionBaseDatos = DriverManager.getConnection(ci.getUrl(),ci.getUsuario(),ci.getPassword());
	                    numConexiones++;
                	} else {
                		logger.error("No existen datos de conexion para el tipo de base de datos indicada");
                	}                	
                }
            } catch (SQLException e) {
                logger.error("Error al obtener la conexion " + e);
            }            
        } else {            
            InitialContext initialContext;
            try {
            	logger.info("Crear conexion mediante Datasource");
                initialContext = new InitialContext();
                if ( conexionBaseDatos == null || conexionBaseDatos.isClosed() ) {
                	
                    DataSource ds = (DataSource) initialContext.lookup(databaseType.getDatasource());
                    conexionBaseDatos = ds.getConnection();
                    numConexiones++;
                }
            } catch (NamingException e) {
                logger.error("> Error con el Datasource" + e);
            } catch (SQLException e) {
                logger.error("> Error obteniendo la conexion" + e);
            }
        }
        logger.info( "Numero de conexiones abiertas " + numConexiones );
        return conexionBaseDatos;
    }

    /**
     * Cierra una conexion a la base de datos.
     */
    public void cerrarConexion( Connection conexionBaseDatos ) {
        try {            
            if ( PersistenceType.getInstancia().getTipoPersistencia() == PersistenceConstants.TIPO_CONEXIONDIRECTA ) {
            	conexionBaseDatos.close();
            } else {
            	conexionBaseDatos.close();
            }
            numConexiones--;
            conexionBaseDatos = null;            
        } catch (SQLException e) {
            logger.error("Error al cerrar la conexion " + e);
        }
        logger.info ( "Numero de conexiones abiertas " + numConexiones );
    }
    
    /**
     * Cierra una conexion a la base de datos.
     */
    public void cerrarConexionServicio( Connection conexionBaseDatos ) throws SQLException {
        try {            
            if ( PersistenceType.getInstancia().getTipoPersistencia() == PersistenceConstants.TIPO_CONEXIONDIRECTA ) {
            	conexionBaseDatos.close();
            } else {
            	conexionBaseDatos.close();
            }
            numConexiones--;
            conexionBaseDatos = null;
        } catch (SQLException e) {
            logger.error("Error al cerrar la conexion " + e);
            throw e;
        }
        logger.info ( "Numero de conexiones abiertas " + numConexiones );
    }

    /**
     * Unica instancia de la clase.
     * @return Instancia
     */
    public static DAOFactory getInstancia() {
        return instancia;
    }
}
